home *** CD-ROM | disk | FTP | other *** search
/ Megadoom II / MEGADOOM II - iso.7z / MEGADOOM II.ISO / doom / editors / map / dmpsmu / source / print.c < prev    next >
C/C++ Source or Header  |  1994-10-31  |  27KB  |  771 lines

  1. /*
  2.    DooM PostScript Maps Utility, by Frans P. de Vries.
  3.  
  4. Derived from:
  5.  
  6.    Doom Editor Utility, by Brendon Wyber and Raphaδl Quinet.
  7.  
  8.    You are allowed to use any parts of this code in another program, as
  9.    long as you give credits to the authors in the documentation and in
  10.    the program itself.  Read the file README for more information.
  11.  
  12.    This program comes with absolutely no warranty.
  13.  
  14.    PRINT.C - Print and Analyze routines.
  15. */
  16.  
  17.  
  18. /* the includes */
  19. #include "dmps.h"
  20. #include "levels.h"
  21. #include "things.h"
  22.  
  23.  
  24. /* global variables */
  25.                 /* if TRUE ('+');        if FALSE ('-')        */
  26. Bool FlagDoublePg = FALSE;    /* print double page;    print normal page     */
  27. Bool FlagQuadplPg = FALSE;    /* print quadruple page; print normal page     */
  28. Bool FlagA4Letter = TRUE;    /* print A4 paper;       print Letter paper    */
  29. Bool FlagBorder   = TRUE;    /* print border;         print no border       */
  30. Bool FlagDecors   = TRUE;    /* print decors;         print no decors       */
  31. Bool FlagEnemies  = TRUE;    /* print enemies;        print no enemies      */
  32. Bool FlagFadeLins = TRUE;    /* fade secret lines;    don't fade sec.lines  */
  33. Bool FlagGoodies  = TRUE;    /* print goodies;        print no goodies      */
  34. Bool FlagLegend   = TRUE;    /* print thing legend;   print no thing legend */
  35. Bool FlagMultPlay = FALSE;    /* print multi things;   print no multi things */
  36. Bool FlagName     = TRUE;    /* print level name;     print no level name   */
  37. Bool FlagPortrait = TRUE;    /* print portrait;       print landscape       */
  38. Bool FlagShdAreas = TRUE;    /* shade secret areas;   don't shade sec.areas */
  39. Bool FlagTeleprts = TRUE;    /* link teleports;       don't link teleports  */
  40. Bool FlagUltraVlc = TRUE;    /* print UV things;      print non-UV things   */
  41. Bool FlagAutoZoom = TRUE;    /* auto-zoom map scale;  default map scale     */
  42.  
  43. BCINT MapCenterX;        /* X coord of map center */
  44. BCINT MapCenterY;        /* Y coord of map center */
  45.  
  46.  
  47. /* map attribute definitions */
  48. #define L_IMPASS 0x01        /* impassible linedef */
  49. #define L_SECRET 0x20        /* secret linedef */
  50. #define L_TELEP1 39        /* one-time teleport linedef */
  51. #define L_TELEPR 97        /* repeatable teleport linedef */
  52. #define L_TELPM1 125        /* one-time monster-only teleport linedef */
  53. #define L_TELPMR 126        /* repeatable monster-only teleport linedef */
  54. #define S_SECRET 9        /* secret sector */
  55. #define T_MULTI  0x10        /* multi-player thing */
  56. #define T_ULTRA  0x04        /* ultra-violence thing */
  57. #define T_NONUV  0x03        /* non ultra-violence thing */
  58.  
  59.  
  60. /*
  61.    read level & print its map
  62. */
  63. void PrintLevel( BCINT episode, BCINT mission)
  64. {
  65.    ReadLevelData( episode, mission);
  66.    /* define map center */
  67.    MapCenterX = (MapMinX + MapMaxX) / 2;
  68.    MapCenterY = (MapMinY + MapMaxY) / 2;
  69.  
  70.    /* initialize, scale & draw the page */
  71.    InitPage( episode, mission, ( UserLvlNm != NULL ? UserLvlNm : LevelName ));
  72.  
  73.    InitScale( MapMaxX - MapMinX, MapMaxY - MapMinY,
  74.           ( UserLvlNm != NULL ? UserLvlNm : LevelName ));
  75.    if (FlagAutoZoom && (FlagName || FlagLegend))
  76.    {
  77.       BCINT n;
  78.       for (n = 0; n < NumVertexes; n++)
  79.      /* rough & fine check for covering name or legend areas */
  80.      if (Vertexes[ n].y > MapCenterY)
  81.         if (CheckScale( Vertexes[ n].x, Vertexes[ n].y))
  82.            break;
  83.       if (n < NumVertexes)
  84.      AdjustScale( MapMaxX - MapMinX, MapMaxY - MapMinY);
  85.    }
  86.  
  87.    PrintMap();
  88.    TermPage();
  89.  
  90.    /* clean up & free space */
  91.    ForgetLevelData();
  92. }
  93.  
  94.  
  95. /*
  96.    draw the actual game map
  97. */
  98. void PrintMap( void)
  99. {
  100.    BCINT n, m;
  101.  
  102.    /* draw the shaded secret Sectors if desired */
  103.    if (FlagShdAreas)
  104.    {
  105.       BCINT l, end;
  106.       BCINT lines[ 100];
  107.  
  108.       InitShades();
  109.  
  110.       /* find all secret Sectors */
  111.       for (n = 0; n < NumSectors; n++)
  112.      if (Sectors[ n].special == S_SECRET)
  113.      {
  114.         end = 0;
  115.  
  116.         /* build list of all LineDefs that make up the Sector */
  117.         for (m = 0; m < NumLineDefs; m++)
  118.         {
  119.            l = SideDefs[ LineDefs[ m].sidedef1].sector;
  120.            if (l != n && LineDefs[ m].sidedef2 != -1)
  121.           l = SideDefs[ LineDefs[ m].sidedef2].sector;
  122.            if (l == n)
  123.           if (end < 100) /* safety check (E3M5 sector 128 has 46 lines) */
  124.              lines[ end++] = m;
  125.           else
  126.           {
  127.              printf( "[Secret sector %d has too many lines for shading.]\n", n);
  128.              break;
  129.           }
  130.         }
  131.         if (m < NumLineDefs) /* extend above safety check */
  132.            break;
  133.  
  134.         /* find LineDef with the most lower-left start Vertex */
  135.         l = 0;
  136.         for (m = 1; m < end; m++)
  137.            if ((Vertexes[ LineDefs[ lines[ l]].start].y > Vertexes[ LineDefs[ lines[ m]].start].y) ||
  138.                (Vertexes[ LineDefs[ lines[ l]].start].y == Vertexes[ LineDefs[ lines[ m]].start].y &&
  139.             Vertexes[ LineDefs[ lines[ l]].start].x > Vertexes[ LineDefs[ lines[ m]].start].x))
  140.           l = m;
  141.         /* put it at front (makes it most probable that list starts with outer
  142.            Sector); saves elaborate checks on which Sector contains which others */
  143.         if (l != 0)
  144.            exch( lines[ 0], lines[ l]);
  145.  
  146.         /* sort list for consecutive Vertices on outer and any inner Sectors
  147.            (eg. E2M1 sector 3 has 4 inner ones), negating "reverse" LineDefs */
  148.         for (m = 0; m < end - 1; m++)
  149.         {
  150.            for (l = m + 1; l < end; l++)
  151.           if (lines[ m] >= 0)
  152.           {
  153.              if (LineDefs[ lines[ m]].end == LineDefs[ lines[ l]].start)
  154.             break;
  155.              if (LineDefs[ lines[ m]].end == LineDefs[ lines[ l]].end)
  156.              {
  157.             lines[ l] = - lines[ l];
  158.             break;
  159.              }
  160.           }
  161.           else /* lines[ m] < 0 */
  162.           {
  163.              if (LineDefs[ - lines[ m]].start == LineDefs[ lines[ l]].start)
  164.             break;
  165.              if (LineDefs[ - lines[ m]].start == LineDefs[ lines[ l]].end)
  166.              {
  167.             lines[ l] = - lines[ l];
  168.             break;
  169.              }
  170.           }
  171.  
  172.            /* put next LineDef behind current one */
  173.            if (l < end)
  174.           exch( lines[ m + 1], lines[ l]);
  175.         }
  176.  
  177.         /* shade the secret Sector */
  178.         PrintShade( 'B', Vertexes[ LineDefs[ lines[ 0]].start].x,
  179.                  Vertexes[ LineDefs[ lines[ 0]].start].y);
  180.         for (m = 0; m < end; m++)
  181.            if (lines[ m] >= 0)
  182.           if (LineDefs[ lines[ 0]].start == LineDefs[ lines[ m]].end)
  183.              break;
  184.           else
  185.              PrintShade( 'N', Vertexes[ LineDefs[ lines[ m]].end].x,
  186.                       Vertexes[ LineDefs[ lines[ m]].end].y);
  187.            else /* lines[ m] < 0 */
  188.           if (LineDefs[ lines[ 0]].start == LineDefs[ - lines[ m]].start)
  189.              break;
  190.           else
  191.              PrintShade( 'N', Vertexes[ LineDefs[ - lines[ m]].start].x,
  192.                       Vertexes[ LineDefs[ - lines[ m]].start].y);
  193.         PrintShade ('S', 0, 0);
  194.  
  195.         /* un-shade any inner Sectors of the secret one */
  196.         l = m + 1;
  197.         while (l < end)
  198.         {
  199.            PrintShade( 'B', Vertexes[ LineDefs[ lines[ l]].start].x,
  200.                 Vertexes[ LineDefs[ lines[ l]].start].y);
  201.            m = l;
  202.            while (m < end)
  203.            {
  204.            if (lines[ m] >= 0)
  205.              if (LineDefs[ lines[ l]].start == LineDefs[ lines[ m]].end)
  206.             break;
  207.              else
  208.             PrintShade( 'N', Vertexes[ LineDefs[ lines[ m]].end].x,
  209.                       Vertexes[ LineDefs[ lines[ m]].end].y);
  210.           else /* lines[ m] < 0 */
  211.              if (LineDefs[ lines[ l]].start == LineDefs[ - lines[ m]].start)
  212.             break;
  213.              else
  214.             PrintShade( 'N', Vertexes[ LineDefs[ - lines[ m]].start].x,
  215.                       Vertexes[ LineDefs[ - lines[ m]].start].y);
  216.           m++;
  217.            }
  218.            PrintShade ('W', 0, 0);
  219.            l = m + 1;
  220.         }
  221.     }
  222.    }
  223.  
  224.    /* draw the LineDefs to form the map */
  225.    InitLines();
  226.  
  227.    for (n = 0; n < NumLineDefs; n++)
  228.       if (FlagFadeLins)
  229.       {
  230.      /* check if Sector on either side of LineDef is secret */
  231.      m = Sectors[ SideDefs[ LineDefs[ n].sidedef1].sector].special;
  232.      if (m != S_SECRET && LineDefs[ n].sidedef2 != -1)
  233.         m = Sectors[ SideDefs[ LineDefs[ n].sidedef2].sector].special;
  234.  
  235.      PrintMapLine( Vertexes[ LineDefs[ n].start].x, Vertexes[ LineDefs[ n].start].y,
  236.                Vertexes[ LineDefs[ n].end].x,   Vertexes[ LineDefs[ n].end].y,
  237.                (LineDefs[ n].flags & L_IMPASS),
  238.                (LineDefs[ n].flags & L_SECRET) || m == S_SECRET);
  239.       }
  240.       else
  241.      PrintMapLine( Vertexes[ LineDefs[ n].start].x, Vertexes[ LineDefs[ n].start].y,
  242.                Vertexes[ LineDefs[ n].end].x,   Vertexes[ LineDefs[ n].end].y,
  243.                (LineDefs[ n].flags & L_IMPASS), FALSE);
  244.  
  245.    /* draw all desired Things */
  246.    InitThings();
  247.  
  248.    for (n = 0; n < NumThings; n++)
  249.       /* check whether multi-player Thing should be printed */
  250.       if (FlagMultPlay || ! (Things[ n].when & T_MULTI))
  251.      /* check whether UV or non-UV Thing should be printed */
  252.      if ((FlagUltraVlc && (Things[ n].when & T_ULTRA)) ||
  253.          (! FlagUltraVlc && (Things[ n].when & T_NONUV)))
  254.      {
  255.         m = Things[ n].type;
  256.         switch( GetThingClass( m))
  257.         {
  258.         case CLASS_START:
  259.            /* always print Player 1 Start, others only if multi-player Things */
  260.            if (FlagMultPlay || m == THING_PLAYER1)
  261.           break;
  262.            else
  263.           continue;
  264.         case CLASS_ENHANCE:
  265.            if (FlagGoodies)
  266.           break;
  267.            else
  268.           continue;
  269.         case CLASS_BONUS:
  270.            if (FlagGoodies)
  271.           break;
  272.            else
  273.           continue;
  274.         case CLASS_WEAPON:
  275.            if (FlagGoodies)
  276.           break;
  277.            else
  278.           continue;
  279.         case CLASS_ENEMY:
  280.            if (FlagEnemies)
  281.           break;
  282.            else
  283.           continue;
  284.         case CLASS_DECOR:
  285.            if (FlagDecors)
  286.           break;
  287.            else
  288.           continue;
  289.         case CLASS_BARREL:
  290.            if (FlagDecors)
  291.           break;
  292.            else
  293.           continue;
  294.         case CLASS_TELEPORT:
  295.            /* always print Teleport Exits */
  296.            break;
  297.         default:
  298.            break;
  299.         }
  300.  
  301.         PrintMapThing( GetThingClass( m), Things[ n].xpos, Things[ n].ypos,
  302.                GetThingRadius( m), Things[ n].angle);
  303.      }
  304.  
  305.    /* draw the Teleport links if desired */
  306.    if (FlagTeleprts)
  307.    {
  308.       BCINT t;
  309.  
  310.       InitLinks();
  311.  
  312.       /* find all (incl. monster-only) teleporting LineDefs */
  313.       for (n = 0; n < NumLineDefs; n++)
  314.      if (LineDefs[ n].type == L_TELEP1 || LineDefs[ n].type == L_TELEPR ||
  315.          LineDefs[ n].type == L_TELPM1 || LineDefs[ n].type == L_TELPMR)
  316.      {
  317.         /* find associated Sector */
  318.         for (m = 0; m < NumSectors; m++)
  319.            if (Sectors[ m].tag == LineDefs[ n].tag)
  320.           if ((t = FindTeleExit( m)) != NumThings)
  321.           {
  322.              /* draw link from LineDef midpoint to teleport exit center */
  323.              PrintTeleLink( (Vertexes[ LineDefs[ n].start].x + Vertexes[ LineDefs[ n].end].x) / 2,
  324.                     (Vertexes[ LineDefs[ n].start].y + Vertexes[ LineDefs[ n].end].y) / 2,
  325.                     Things[ t].xpos, Things[ t].ypos);
  326.              break;
  327.           }
  328.  
  329.         if (m == NumSectors) /* safety check */
  330.            printf( "[No sector tagged %d found with teleport exit.]\n", LineDefs[ n].tag);
  331.      }
  332.    }
  333. }
  334.  
  335.  
  336. /*
  337.    find a Teleport Exit inside the given Sector
  338. */
  339. BCINT FindTeleExit( BCINT sector)
  340. {
  341.    BCINT n, s, t;
  342.    BCINT ll, lr, ul, ur;         /* lower/upper left/right quadrants */
  343.    BCINT x0, y0, x1, y1, x2, y2; /* teleport exit point & LineDef end points */
  344.  
  345.    /* find all teleport exits */
  346.    for (t = 0; t < NumThings; t++)
  347.       if (Things[ t].type == THING_TELEPORT)
  348.       {
  349.      ll = 0; lr = 0; ul = 0; ur = 0;
  350.      x0 = Things[ t].xpos;
  351.      y0 = Things[ t].ypos;
  352.  
  353.      /* find all LineDefs that make up the Sector */
  354.      for (n = 0; n < NumLineDefs; n++)
  355.      {
  356.         s = SideDefs[ LineDefs[ n].sidedef1].sector;
  357.         if (s != sector && LineDefs[ n].sidedef2 != -1)
  358.            s = SideDefs[ LineDefs[ n].sidedef2].sector;
  359.         if (s == sector)
  360.         {
  361.            x1 = Vertexes[ LineDefs[ n].start].x;
  362.            y1 = Vertexes[ LineDefs[ n].start].y;
  363.            x2 = Vertexes[ LineDefs[ n].end].x;
  364.            y2 = Vertexes[ LineDefs[ n].end].y;
  365.  
  366.            /* determine position of Vertices relative to teleport exit */
  367.            /* don't swap < & >= for <= & > : the telelinks inside the mid-east
  368.           building on MAP13 will be misconnected; all the more indication
  369.           that this whole algorithm sucks, but it's the only one I know
  370.           that works at least for all DOOM and most DOOM ][ maps */
  371.            ll += (x0 >= x1) && (y0 >= y1);
  372.            lr += (x0 <  x1) && (y0 >= y1);
  373.            ul += (x0 >= x1) && (y0 <  y1);
  374.            ur += (x0 <  x1) && (y0 <  y1);
  375.            ll += (x0 >= x2) && (y0 >= y2);
  376.            lr += (x0 <  x2) && (y0 >= y2);
  377.            ul += (x0 >= x2) && (y0 <  y2);
  378.            ur += (x0 <  x2) && (y0 <  y2);
  379.         }
  380.      }
  381.      /* check all 4 quadrants whether teleport exit is surrounded by LineDefs */
  382.      if (ll > 0 && lr > 0 && ul > 0 && ur > 0)
  383.         break;
  384.  
  385.      /* check (by diagonal opposites) whether it's worth computing perpendicular
  386.         intersects; actually, finding the sector's linedefs again might be less
  387.         efficient than computing the intersects everytime, but this stuff really
  388.         came in as an afterthought because of 3 teleport links in E3M6 & E3M9 */
  389.      if (ll * ur > 0 || lr * ul > 0)
  390.      {
  391.         /* find all LineDefs that make up the Sector */
  392.         for (n = 0; n < NumLineDefs; n++)
  393.         {
  394.            s = SideDefs[ LineDefs[ n].sidedef1].sector;
  395.            if (s != sector && LineDefs[ n].sidedef2 != -1)
  396.           s = SideDefs[ LineDefs[ n].sidedef2].sector;
  397.            if (s == sector)
  398.            {
  399.           BCINT xi, yi;     /* intersect point */
  400.           BCINT A, B, C, D; /* equation coefficients */
  401.           long  E, F, det;  /* & determinant */
  402.  
  403.           x1 = Vertexes[ LineDefs[ n].start].x;
  404.           y1 = Vertexes[ LineDefs[ n].start].y;
  405.           x2 = Vertexes[ LineDefs[ n].end].x;
  406.           y2 = Vertexes[ LineDefs[ n].end].y;
  407.  
  408.           /* a little geometry of similar triangles results in the following
  409.              relations for computing the intersect point of the LineDef and
  410.              its perpendicular going through the teleport exit:
  411.  
  412.             y2 - y1   xi - x0       yi - y1   y2 - yi
  413.             ------- = -------  and  ------- = -------
  414.             x2 - x1   y0 - yi       xi - x1   x2 - xi
  415.  
  416.              this can be rewritten into 2 equations in xi and yi, which
  417.              can then easily be solved for:
  418.  
  419.             (y1 - y2) * xi + (x2 - x1) * yi = x2 * y1 - x1 * y2
  420.             (x2 - x1) * xi + (y2 - y1) * yi = x0 * (x2-x1) - y0 * (y2-y1)
  421.           */
  422.           A = y1 - y2; D = -A;
  423.           B = x2 - x1; C = B;
  424.           E = x2 * y1 - x1 * y2;
  425.           F = x0 * C  + y0 * D;
  426.           if ((det = A * D - B * C) != 0)
  427.           {
  428.              xi = ( D * E - C * F ) / det;
  429.              yi = ( A * F - B * E ) / det;
  430.  
  431.              /* check if intersect is outside LineDef */
  432.              if ((xi < x1 && xi < x2) || (xi > x1 && xi > x2) ||
  433.              (yi < y1 && yi < y2) || (yi > y1 && yi > y2))
  434.              {
  435.             xi = x0; /* set dummy intersect not in any quadrant */
  436.             yi = y0;
  437.              }
  438.           }
  439.           else /* avoiding the unlikely but dreaded division by zero... */
  440.           {
  441.              xi = x0; /* ditto */
  442.              yi = y0;
  443.           }
  444.  
  445.           /* determine position of intersect relative to teleport exit */
  446.           ll += (x0 > xi) && (y0 > yi);
  447.           lr += (x0 < xi) && (y0 > yi);
  448.           ul += (x0 > xi) && (y0 < yi);
  449.           ur += (x0 < xi) && (y0 < yi);
  450.            }
  451.         }
  452.         /* check all 4 quadrants again for surrounding perpendicular intersects */
  453.         if (ll > 0 && lr > 0 && ul > 0 && ur > 0)
  454.            break;
  455.      }
  456.       }
  457.    return t;
  458. }
  459.  
  460.  
  461. /*
  462.    display all print flags
  463. */
  464. void DisplayFlags( void)
  465. {
  466.    printf( "Print flags:\n");
  467.    printf( "-----------\n");
  468.    printf( "%s\n", ( FlagDoublePg ? "+2\tuse double page"
  469.                   : "-2\tuse normal page" ));
  470.    printf( "%s\n", ( FlagQuadplPg ? "+4\tuse quadruple page"
  471.                   : "-4\tuse normal page" ));
  472.    printf( "%s\n", ( FlagA4Letter ? "+A\tuse A4 paper size"
  473.                   : "-A\tuse Letter paper size" ));
  474.    printf( "%s\n", ( FlagBorder   ? "+B\tprint border around map"
  475.                   : "-B\tprint no border around map" ));
  476.    printf( "%s\n", ( FlagDecors   ? "+D\tprint all decorations & barrels"
  477.                   : "-D\tprint no decorations & barrels" ));
  478.    printf( "%s\n", ( FlagEnemies  ? "+E\tprint all enemies"
  479.                   : "-E\tprint no enemies" ));
  480.    printf( "%s\n", ( FlagFadeLins ? "+F\tfade secret lines"
  481.                   : "-F\tdon't fade secret lines" ));
  482.    printf( "%s\n", ( FlagGoodies  ? "+G\tprint all goodies (weapons/bonuses/enhancements)"
  483.                   : "-G\tprint no goodies (weapons/bonuses/enhancements)" ));
  484.    printf( "%s\n", ( FlagLegend   ? "+L\tprint legend above map"
  485.                   : "-L\tprint no legend above map" ));
  486.    printf( "%s\n", ( FlagMultPlay ? "+M\tprint multi-player things"
  487.                   : "-M\tprint no multi-player things" ));
  488.    printf( "%s\n", ( FlagName     ? "+N\tprint name above map"
  489.                   : "-N\tprint no name above map" ));
  490.    printf( "%s\n", ( FlagPortrait ? "+P\tuse Portrait orientation"
  491.                   : "-P\tuse Landscape orientation" ));
  492.    printf( "%s\n", ( FlagShdAreas ? "+S\tshade secret areas"
  493.                   : "-S\tdon't shade secret areas" ));
  494.    printf( "%s\n", ( FlagTeleprts ? "+T\tlink teleports"
  495.                   : "-T\tdon't link teleports" ));
  496.    printf( "%s\n", ( FlagUltraVlc ? "+U\tprint things for Ultra-Violence skill"
  497.                   : "-U\tprint things below Ultra-Violence skill" ));
  498.    printf( "%s\n", ( FlagAutoZoom ? "+Z\tauto-zoom map scale"
  499.                   : "-Z\tdefault map scale" ));
  500. }
  501.  
  502.  
  503. /*
  504.    set a print flag
  505. */
  506. void SetFlag( char flag, char val)
  507. {
  508.    switch( flag)
  509.    {
  510.    case '2':
  511.       FlagDoublePg = ( val == '+' ? TRUE : FALSE );
  512.       printf( "%s\n", ( FlagDoublePg ? "+2\tuse double page"
  513.                      : "-2\tuse normal page" ));
  514.       if (FlagDoublePg && FlagQuadplPg)
  515.      SetFlag( '4', '-');
  516.       break;
  517.    case '4':
  518.       FlagQuadplPg = ( val == '+' ? TRUE : FALSE );
  519.       printf( "%s\n", ( FlagQuadplPg ? "+4\tuse quadruple page"
  520.                      : "-4\tuse normal page" ));
  521.       if (FlagQuadplPg && FlagDoublePg)
  522.      SetFlag( '2', '-');
  523.       break;
  524.    case 'A':
  525.       FlagA4Letter = ( val == '+' ? TRUE : FALSE );
  526.       printf( "%s\n", ( FlagA4Letter ? "+A\tuse A4 paper size"
  527.                      : "-A\tuse Letter paper size" ));
  528.       break;
  529.    case 'B':
  530.       FlagBorder   = ( val == '+' ? TRUE : FALSE );
  531.       printf( "%s\n", ( FlagBorder   ? "+B\tprint border around map"
  532.                      : "-B\tprint no border around map" ));
  533.       break;
  534.    case 'D':
  535.       FlagDecors   = ( val == '+' ? TRUE : FALSE );
  536.       printf( "%s\n", ( FlagDecors   ? "+D\tprint all decorations & barrels"
  537.                      : "-D\tprint no decorations & barrels" ));
  538.       break;
  539.    case 'E':
  540.       FlagEnemies  = ( val == '+' ? TRUE : FALSE );
  541.       printf( "%s\n", ( FlagEnemies  ? "+E\tprint all enemies"
  542.                      : "-E\tprint no enemies" ));
  543.       break;
  544.    case 'F':
  545.       FlagFadeLins = ( val == '+' ? TRUE : FALSE );
  546.       printf( "%s\n", ( FlagFadeLins ? "+F\tfade secret lines"
  547.                      : "-F\tdon't fade secret lines" ));
  548.       break;
  549.    case 'G':
  550.       FlagGoodies  = ( val == '+' ? TRUE : FALSE );
  551.       printf( "%s\n", ( FlagGoodies  ? "+G\tprint all goodies (weapons/bonuses/enhancements)"
  552.                      : "-G\tprint no goodies (weapons/bonuses/enhancements)" ));
  553.       break;
  554.    case 'L':
  555.       FlagLegend   = ( val == '+' ? TRUE : FALSE );
  556.       printf( "%s\n", ( FlagLegend   ? "+L\tprint legend above map"
  557.                      : "-L\tprint no legend above map" ));
  558.       break;
  559.    case 'M':
  560.       FlagMultPlay = ( val == '+' ? TRUE : FALSE );
  561.       printf( "%s\n", ( FlagMultPlay ? "+M\tprint multi-player things"
  562.                      : "-M\tprint no multi-player things" ));
  563.       break;
  564.    case 'N':
  565.       FlagName     = ( val == '+' ? TRUE : FALSE );
  566.       printf( "%s\n", ( FlagName     ? "+N\tprint name above map"
  567.                      : "-N\tprint no name above map" ));
  568.       break;
  569.    case 'P':
  570.       FlagPortrait = ( val == '+' ? TRUE : FALSE );
  571.       printf( "%s\n", ( FlagPortrait ? "+P\tuse Portrait orientation"
  572.                      : "-P\tuse Landscape orientation" ));
  573.       break;
  574.    case 'S':
  575.       FlagShdAreas = ( val == '+' ? TRUE : FALSE );
  576.       printf( "%s\n", ( FlagShdAreas ? "+S\tshade secret areas"
  577.                      : "-S\tdon't shade secret areas" ));
  578.       break;
  579.    case 'T':
  580.       FlagTeleprts = ( val == '+' ? TRUE : FALSE );
  581.       printf( "%s\n", ( FlagTeleprts ? "+T\tlink teleports"
  582.                      : "-T\tdon't link teleports" ));
  583.       break;
  584.    case 'U':
  585.       FlagUltraVlc = ( val == '+' ? TRUE : FALSE );
  586.       printf( "%s\n", ( FlagUltraVlc ? "+U\tprint things for Ultra-Violence skill"
  587.                      : "-U\tprint things below Ultra-Violence skill" ));
  588.       break;
  589.    case 'Z':
  590.       FlagAutoZoom = ( val == '+' ? TRUE : FALSE );
  591.       printf( "%s\n", ( FlagAutoZoom ? "+Z\tauto-zoom map scale"
  592.                      : "-Z\tdefault map scale" ));
  593.       break;
  594.    }
  595. }
  596.  
  597.  
  598. /* power-ups local array index names */
  599. #define Shotgun  0
  600. #define Cmbatgun 1
  601. #define Chaingun 2
  602. #define RcktLnch 3
  603. #define Plasmagn 4
  604. #define Bfg9000  5
  605. #define Chainsaw 6
  606. #define Berserk  7
  607. #define Backpack 8
  608. #define SecurArm 9
  609. #define CmbatArm 10
  610. #define SoulSphr 11
  611. #define MegaSphr 12
  612. #define BlurArtf 13
  613. #define InvlnArt 14
  614. #define RadSuit  15
  615. #define CompMap  16
  616. #define LiteAmp  17
  617.  
  618. /* enemies local array index names */
  619. #define Human    0
  620. #define Sergeant 1
  621. #define Commando 2
  622. #define Imp      3
  623. #define Demon    4
  624. #define Spectre  5
  625. #define LostSoul 6
  626. #define CacoDmn  7
  627. #define PainElem 8
  628. #define Mancubus 9
  629. #define Revenant 10
  630. #define Knight   11
  631. #define Baron    12
  632. #define Arachno  13
  633. #define ArchVile 14
  634. #define CyberDmn 15
  635. #define SpiderBs 16
  636. #define Wolf3dSS 17
  637.  
  638. /*
  639.    read level & analyze its statistics
  640. */
  641. void AnalyzeLevel( BCINT episode, BCINT mission)
  642. {
  643.    BCINT classes[ 9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  644.    BCINT powrups[ 18] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  645.    BCINT enemies[ 18] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  646.    BCINT n, m, secret = 0, telept = 0;
  647.  
  648.    ReadLevelData( episode, mission);
  649.  
  650.    /* count Thing classes, Power-Ups types & Enemies types */
  651.    for (n = 0; n < NumThings; n++)
  652.       /* check whether multi-player Thing should be counted */
  653.       if (FlagMultPlay || ! (Things[ n].when & T_MULTI))
  654.      /* check whether UV or non-UV Thing should be counted */
  655.      if ((FlagUltraVlc && (Things[ n].when & T_ULTRA)) ||
  656.          (! FlagUltraVlc && (Things[ n].when & T_NONUV)))
  657.      {
  658.         m = Things[ n].type;
  659.         classes[ GetThingClass( m)]++;
  660.  
  661.         if (GetThingClass( m) == CLASS_WEAPON || GetThingClass( m) == CLASS_ENHANCE)
  662.            switch( m)
  663.            {
  664.           case THING_SHOTGUN:    powrups[ Shotgun ]++; break;
  665.           case THING_COMBATGUN:    powrups[ Cmbatgun]++; break;
  666.           case THING_CHAINGUN:    powrups[ Chaingun]++; break;
  667.           case THING_LAUNCHER:    powrups[ RcktLnch]++; break;
  668.           case THING_PLASMAGUN:    powrups[ Plasmagn]++; break;
  669.           case THING_BFG9000:    powrups[ Bfg9000 ]++; break;
  670.           case THING_CHAINSAW:    powrups[ Chainsaw]++; break;
  671.           case THING_BERSERK:    powrups[ Berserk ]++; break;
  672.           case THING_BACKPACK:    powrups[ Backpack]++; break;
  673.           case THING_GREENARMOR:powrups[ SecurArm]++; break;
  674.           case THING_BLUEARMOR:    powrups[ CmbatArm]++; break;
  675.           case THING_SOULSPHERE:powrups[ SoulSphr]++; break;
  676.           case THING_MEGASPHERE:powrups[ MegaSphr]++; break;
  677.           case THING_BLURSPHERE:powrups[ BlurArtf]++; break;
  678.           case THING_INVULN:    powrups[ InvlnArt]++; break;
  679.           case THING_RADSUIT:    powrups[ RadSuit ]++; break;
  680.           case THING_COMPMAP:    powrups[ CompMap ]++; break;
  681.           case THING_LITEAMP:    powrups[ LiteAmp ]++; break;
  682.           default: break;    /* ignore ammo boxes & keys */
  683.            }
  684.  
  685.         if (GetThingClass( m) == CLASS_ENEMY)
  686.            switch( m)
  687.            {
  688.           case THING_HUMAN:    enemies[ Human   ]++; break;
  689.           case THING_SERGEANT:    enemies[ Sergeant]++; break;
  690.           case THING_COMMANDO:    enemies[ Commando]++; break;
  691.           case THING_IMP:    enemies[ Imp     ]++; break;
  692.           case THING_DEMON:    enemies[ Demon   ]++; break;
  693.           case THING_SPECTRE:    enemies[ Spectre ]++; break;
  694.           case THING_LOSTSOUL:    enemies[ LostSoul]++; break;
  695.           case THING_CACODEMON:    enemies[ CacoDmn ]++; break;
  696.           case THING_PAINELEM:    enemies[ PainElem]++; break;
  697.           case THING_MANCUBUS:    enemies[ Mancubus]++; break;
  698.           case THING_REVENANT:    enemies[ Revenant]++; break;
  699.           case THING_KNIGHT:    enemies[ Knight  ]++; break;
  700.           case THING_BARON:    enemies[ Baron   ]++; break;
  701.           case THING_ARACHNO:    enemies[ Arachno ]++; break;
  702.           case THING_ARCHVILE:    enemies[ ArchVile]++; break;
  703.           case THING_CYBERDEMON:enemies[ CyberDmn]++; break;
  704.           case THING_SPIDERBOSS:enemies[ SpiderBs]++; break;
  705.           case THING_WOLF3DSS:    enemies[ Wolf3dSS]++; break;
  706.            }
  707.      }
  708.  
  709.    /* count secret Sectors & teleporting LineDefs */
  710.    for (n = 0; n < NumSectors; n++)
  711.       if (Sectors[ n].special == S_SECRET)
  712.      secret++;
  713.    for (n = 0; n < NumLineDefs; n++)
  714.       if (LineDefs[ n].type == L_TELEP1 || LineDefs[ n].type == L_TELEPR)
  715.      telept++;
  716.  
  717.    /* print all statistics */
  718.    if (Commercial) {
  719.       printf( "Statistics of level MAP%02d: %s\n", mission,
  720.            ( UserLvlNm != NULL ? UserLvlNm : LevelName ));
  721.       printf( "=========================\n\n");
  722.    }
  723.    else {
  724.       printf( "Statistics of level E%dM%d: %s\n", episode, mission,
  725.            ( UserLvlNm != NULL ? UserLvlNm : LevelName ));
  726.       printf( "========================\n\n");
  727.    }
  728.  
  729.    printf( "MapDim:\t  MaxX\t  MinX\t SizeX\t  MaxY\t  MinY\t SizeY\n");
  730.    printf( "\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\n",
  731.         MapMaxX, MapMinX, MapMaxX - MapMinX, MapMaxY, MapMinY, MapMaxY - MapMinY);
  732.  
  733.    printf( "\n");
  734.    printf( "Struct:\tThings\tVertxs\tLinDfs\tTelePt\tSidDfs\tSectrs\tSecret\n");
  735.    printf( "\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\n",
  736.         NumThings, NumVertexes, NumLineDefs, telept, NumSideDefs, NumSectors, secret);
  737.  
  738.    printf( "\n");
  739.    printf( "Things:\t START\tTLPORT\t BONUS\tWEAPON\tENHANC\t ENEMY\t DECOR\tBARREL\n");
  740.    printf( "\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\n",
  741.         classes[ CLASS_START],   classes[ CLASS_TELEPORT], classes[ CLASS_BONUS], classes[ CLASS_WEAPON],
  742.         classes[ CLASS_ENHANCE], classes[ CLASS_ENEMY],    classes[ CLASS_DECOR], classes[ CLASS_BARREL]);
  743.    if (classes[ CLASS_UNKNOWN] != 0)
  744.       printf( "Things:\tUNKNOWN\t%6d\n", classes[ CLASS_UNKNOWN]);
  745.  
  746.    printf( "\n");
  747.    printf( "PowrUps:SHOTGN\tCOMBAT\tCHAING\tRCKTLR\tPLASMA\t BFG9K\tCHNSAW\tBERSRK\tBCKPCK\n");
  748.    printf( "\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\n",
  749.         powrups[ Shotgun], powrups[ Cmbatgun], powrups[ Chaingun], powrups[ RcktLnch], powrups[ Plasmagn],
  750.         powrups[ Bfg9000], powrups[ Chainsaw], powrups[ Berserk], powrups[ Backpack]);
  751.    printf( "\tGRNARM\tBLUARM\tSOULSP\tMEGASP\tBLURAF\tINVLAF\tRDSUIT\tCMPMAP\tLITAMP\n");
  752.    printf( "\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\n",
  753.         powrups[ SecurArm], powrups[ CmbatArm], powrups[ SoulSphr], powrups[ MegaSphr], powrups[ BlurArtf],
  754.         powrups[ InvlnArt], powrups[ RadSuit], powrups[ CompMap], powrups[ LiteAmp]);
  755.  
  756.    printf( "\n");
  757.    printf( "Enemies: HUMAN\t SARGE\tCOMNDO\t   IMP\t DEMON\tSPECTR\tLOSTSL\tCACODM\tPNELEM\n");
  758.    printf( "\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\n",
  759.         enemies[ Human], enemies[ Sergeant], enemies[ Commando], enemies[ Imp], enemies[ Demon],
  760.         enemies[ Spectre], enemies[ LostSoul], enemies[ CacoDmn], enemies[ PainElem]);
  761.    printf( "\tMANCBS\tREVENT\tKNIGHT\t BARON\tARCHNO\tARVILE\tCYBERD\tSPIDER\tWOLFSS\n");
  762.    printf( "\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\t%6d\n",
  763.         enemies[ Mancubus], enemies[ Revenant], enemies[ Knight], enemies[ Baron], enemies[ Arachno],
  764.         enemies[ ArchVile], enemies[ CyberDmn], enemies[ SpiderBs], enemies[ Wolf3dSS]);
  765.  
  766.    /* clean up & free space */
  767.    ForgetLevelData();
  768. }
  769.  
  770. /* end of file */
  771.